{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Fashion-MNIST Image Classification with TensorFlow\n",
    "\n",
    "This notebook demonstrates how to implement a deep neural network image classification model on Fashion-MNIST using TensorFlow Estimator API. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "PROJECT = 'my-project-id' # REPLACE WITH YOUR PROJECT ID\n",
    "BUCKET = 'my-bucket-name' # REPLACE WITH YOUR BUCKET NAME\n",
    "REGION = 'us-central1' # REPLACE WITH YOUR BUCKET REGION e.g. us-central1\n",
    "MODEL_TYPE='dnn'       # deep neural network\n",
    "\n",
    "# do not change these\n",
    "os.environ['PROJECT'] = PROJECT\n",
    "os.environ['BUCKET'] = BUCKET\n",
    "os.environ['REGION'] = REGION\n",
    "os.environ['MODEL_TYPE'] = MODEL_TYPE\n",
    "os.environ['TFVERSION'] = '1.8'  # Tensorflow version"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%bash\n",
    "gcloud config set project $PROJECT\n",
    "gcloud config set compute/region $REGION\n",
    "gcloud storage rm --recursive --continue-on-error gs://${BUCKET}/fashion/trained_${MODEL_TYPE}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The messages above in pink look like errors, but they are just warnings. Don't worry about the exception mentioning a file that could not be removed. The command that caused it simply tried to delete any previous models in case you are re-running this notebook."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import shutil\n",
    "import os\n",
    "import tensorflow as tf\n",
    "print(tf.__version__)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Exploring the data\n",
    "\n",
    "Let's download  Fashion MNIST data and examine the shape. Take note of the numbers you will get. You will use them throughout this notebook.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#The copyright for Fashion-MNIST is held by Zalando SE.\n",
    "#Fashion-MNIST is licensed under the MIT License.\n",
    "#You can learn more about the Fashion-MNIST dataset  \n",
    "#from https://github.com/zalandoresearch/fashion-mnist\n",
    "(train_images, train_labels), (test_images, test_labels) = tf.keras.datasets.fashion_mnist.load_data()\n",
    "print(\"Done\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Convert the dataset into the format needed for the classifier\n",
    "train_images = train_images.astype('float32')\n",
    "test_images = test_images.astype('float32')\n",
    "train_labels = train_labels.astype('int32')\n",
    "test_labels = test_labels.astype('int32')\n",
    "\n",
    "print(train_images.shape)\n",
    "print(train_labels.shape)\n",
    "print(test_images.shape)\n",
    "print(test_labels.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "HEIGHT=28\n",
    "WIDTH=28\n",
    "NCLASSES=10\n",
    "IMGNO=12\n",
    "\n",
    "#Take a look at a sample image from the dataset\n",
    "import matplotlib.pyplot as plt\n",
    "plt.imshow(train_images[IMGNO].reshape(HEIGHT, WIDTH));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tf.logging.set_verbosity(tf.logging.INFO)\n",
    "\n",
    "#define a training input function\n",
    "train_input_fn = tf.estimator.inputs.numpy_input_fn(\n",
    "    x={'image': train_images},\n",
    "    y=train_labels,\n",
    "    num_epochs=None,  \n",
    "    shuffle=True,  \n",
    "    batch_size=600,\n",
    "    queue_capacity=5000\n",
    "  )\n",
    "\n",
    "#define an input function for evaluation of the accuracy metric using a test dataset\n",
    "test_input_fn = tf.estimator.inputs.numpy_input_fn(\n",
    "    x={'image': test_images},\n",
    "    y=test_labels,\n",
    "    num_epochs=1,\n",
    "    shuffle=False,\n",
    "    queue_capacity=5000\n",
    "  )\n",
    "\n",
    "#create a Deep Neural Network based classifier using 3 hidden layers, 100 neurons each,\n",
    "#and classifying the input into 1 of 10 classes (i.e. categories). \n",
    "model = tf.estimator.DNNClassifier(\n",
    "  feature_columns=[tf.feature_column.numeric_column('image', shape=[HEIGHT, WIDTH])],\n",
    "  hidden_units=[100, 100, 100],\n",
    "  n_classes = NCLASSES,\n",
    "  model_dir = 'gs://{}/fashion/trained_{}'.format(BUCKET, MODEL_TYPE)\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Check your understanding\n",
    "\n",
    "If the previous cell executed successfully, it should have logged an output similar to the following:\n",
    "\n",
    "<pre>\n",
    "INFO:tensorflow:Using default config.\n",
    "INFO:tensorflow:Using config: {'_save_checkpoints_secs': 600, '_session_config': None, '_keep_checkpoint_max': 5, '_task_type': 'worker', '_train_distribute': None, '_is_chief': True, '_cluster_spec': <tensorflow.python.training.server_lib.ClusterSpec object at 0x7f1d5e26d810>, '_evaluation_master': '', '_save_checkpoints_steps': None, '_keep_checkpoint_every_n_hours': 10000, '_service': None, '_num_ps_replicas': 0, '_tf_random_seed': None, '_master': '', '_num_worker_replicas': 1, '_task_id': 0, '_log_step_count_steps': 100, '_model_dir': 'gs://qwiklabs-gcp-27eb45524d98e9a5/fashion/trained_dnn', '_global_id_in_cluster': 0, '_save_summary_steps': 100}\n",
    "</pre>\n",
    "\n",
    "Go ahead and run the next code cell to begin training, and then return back to answer the following question:\n",
    "\n",
    "\n",
    "\n",
    "**Quiz:** Remember that the <code>train_input_fn</code> method sets the <code>num_epochs</code> parameter, i.e. the number of epochs for training to be <code>None</code>. This means that the duration of training depends on the number of steps. Recall that earlier in this notebook you learned that the shape of the training dataset is 60000x28x28 meaning that there are 60000 training examples. If the number of training steps is set to be 1000 when training the model, and the train_input_fn uses a batch size of 600, how many epochs of training does the deep neural net get?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "codeCollapsed": false
   },
   "outputs": [],
   "source": [
    "#Train the model\n",
    "model.train(input_fn = train_input_fn, steps = 1000)\n",
    "\n",
    "#Evaluate accuracy of the trained model\n",
    "accuracy_score = model.evaluate(input_fn=test_input_fn)[\"accuracy\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## DO NOT PROCEED UNTIL YOU CAN SEE THE ACCURACY SCORE\n",
    "\n",
    "If the training finished successfully, you should see an output above similar to the following:\n",
    "\n",
    "<pre>\n",
    "INFO:tensorflow:Done running local_init_op.\n",
    "INFO:tensorflow:Finished evaluation at ...\n",
    "INFO:tensorflow:Saving dict for global step 1000: accuracy = ..., average_loss = ..., global_step = ..., loss = ...\n",
    "</pre>\n",
    "\n",
    "Due to random seeds, your accuracy may vary. In the upcoming labs you will see methods to improve the performance of your image classifier. \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Monitoring training with TensorBoard\n",
    "\n",
    "Use this cell to launch tensorboard"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from google.datalab.ml import TensorBoard\n",
    "TensorBoard().start('gs://{}/fashion/trained_{}'.format(BUCKET, MODEL_TYPE))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for pid in TensorBoard.list()['pid']:\n",
    "  TensorBoard().stop(pid)\n",
    "  print 'Stopped TensorBoard with pid {}'.format(pid)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<pre>\n",
    "# Copyright 2017 Google Inc. All Rights Reserved.\n",
    "#\n",
    "# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
    "# you may not use this file except in compliance with the License.\n",
    "# You may obtain a copy of the License at\n",
    "#\n",
    "#      http://www.apache.org/licenses/LICENSE-2.0\n",
    "#\n",
    "# Unless required by applicable law or agreed to in writing, software\n",
    "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
    "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
    "# See the License for the specific language governing permissions and\n",
    "# limitations under the License.\n",
    "</pre>"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.15"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
